// This file is part of OpenMeca, an easy software to do mechanical simulation.
//
// Author(s)    :  - Damien ANDRE  <openmeca@gmail.com>
//
// Copyright (C) 2012 Damien ANDRE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


#include "boost/lexical_cast.hpp"

#include "OpenMeca/GlobalSetting/UnitManager.hpp"
#include "OpenMeca/Core/GlobalSettingCommonProperty.hpp"
#include "OpenMeca/Util/Dimension.hpp"
#include "OpenMeca/Util/Unit.hpp"


namespace OpenMeca
{
  namespace GlobalSetting
  {

    void
    UnitManager::Init()
    {
      Core::Singleton< Core::GlobalSettingCommonProperty<UnitManager> >::Get();
      Core::Singleton<UnitManager>::Get().ReadXmlFile();
    }

    const std::string
    UnitManager::GetStrType()
    {
      return "UnitManager";
    }

    

    UnitManager::UnitManager()
      :Core::GlobalSettingInterface<UnitManager>()
    {
      
    }
    
   
    UnitManager::~UnitManager()
    {
    }

    std::string 
    UnitManager::GetClassId() const
    {
      return GetStrType();
    }

    void UnitManager::ReadXmlFile()
    {
       std::cout << "Build units...";

      QDomDocument doc("mydocument");
      QFile& file = OpenXmlConfigFile();
      assert(doc.setContent(&file));
      QDomNode n = doc.firstChild();
      while (!n.isNull()) 
	{
	  if (n.isElement()) 
	    {
	      QDomElement e = n.toElement();
	      if (e.tagName()==QString(GetClassId().c_str()))
		{
		  QDomNode n1 = e.firstChild ();
		  while (!n1.isNull()) 
		    {
		      if (n1.isElement()) 
			{
			  QDomElement e1(n1.toElement());
			  AddDimension(e1);
			}
		      n1 = n1.nextSibling();
		    }
		}
	    }
	  n = n.nextSibling();
	}
      std::cout << "ok" << std::endl;
    }
    
 
    void UnitManager::AddDimension(QDomElement& e)
    {
      assert(e.tagName().toStdString() ==  Util::Dimension::GetStrType());

      //Read and check xml attributes
      const std::string name       = e.attribute ("Name").toStdString();
      const std::string userChoice = e.attribute ("UserChoice").toStdString();
      assert(!name.empty() && !userChoice.empty());
      
      Util::Dimension& dim = *new Util::Dimension(name);
      
      QDomNode n1 = e.firstChild ();
      while (!n1.isNull()) 
	{
	  if (n1.isElement()) 
	    {
	      QDomElement e1(n1.toElement());
	      AddUnit(e1, dim);
	    }
	  n1 = n1.nextSibling();
	}
      

      dim.SetSiUnit();
      dim.SetUserChoiceUnit(dim.GetUnit(userChoice));
    }

    void UnitManager::AddUnit(QDomElement& e, Util::Dimension& dim)
    {
      assert(e.tagName().toStdString() ==  Util::Unit::GetStrType());
      const std::string name = e.attribute("Name").toStdString();
      const std::string symbol = e.attribute("Symbol").toStdString();
      const std::string factor = e.attribute("Factor").toStdString();
      assert(!name.empty() && !symbol.empty() && !factor.empty());
      
      double factorValue = 0.;
      try
        {
	  factorValue = boost::lexical_cast<double>(factor);
        }
      catch(boost::bad_lexical_cast &)
        {
	  std::cerr << "Reading units, cannot convert " 
		    << factor 
		    << " to number, programm will stop"
		    << std::endl;
	  assert(0);
        }
      assert(factorValue != 0.);
      
      new Util::Unit(dim, name, symbol, factorValue);
    }


    void UnitManager::WriteXmlFile()
    {
      assert(0);//TODO      
    }

  }
}
